/**
 * 应用配置服务
 *
 * @fileoverview 提供应用配置的数据库存储和管理功能，支持增删改查操作。
 * 实现"数据库优先，文件兜底"的配置加载策略。
 *
 * 核心功能：
 * - 配置的数据库存储和检索
 * - 配置的增删改查操作
 * - 配置分类和权限管理
 * - 配置类型转换和验证
 * - 与文件配置的集成
 *
 * @author System
 * @version 1.0.0
 * @since 2024
 */

import type { AppConfig } from '@shared/types/config'
import { PrismaClient } from '@prisma/client'
import { getLogger } from '../logger/index'

/**
 * 配置项接口
 */
export interface ConfigItem {
  id: number
  config_key: string
  config_value: string
  config_type: 'string' | 'number' | 'boolean' | 'object' | 'array'
  category: string
  description?: string
  is_public: boolean
  is_system: boolean
  created_at: Date
  updated_at: Date
}

/**
 * 创建配置项请求
 */
export interface CreateConfigRequest {
  config_key: string
  config_value: any
  config_type?: 'string' | 'number' | 'boolean' | 'object' | 'array'
  category?: string
  description?: string
  is_public?: boolean
  is_system?: boolean
}

/**
 * 更新配置项请求
 */
export interface UpdateConfigRequest {
  config_value?: any
  config_type?: 'string' | 'number' | 'boolean' | 'object' | 'array'
  category?: string
  description?: string
  is_public?: boolean
}

/**
 * 应用配置服务类
 *
 * @description 管理应用程序配置的数据库存储，提供完整的CRUD操作。
 * 支持配置分类、类型转换、权限控制等高级功能。
 */
export class ConfigService {
  private prisma: PrismaClient
  private logger: any
  private isDbAvailable = true

  constructor() {
    this.prisma = new PrismaClient()
    this.logger = getLogger()

    // 测试数据库连接
    this.testDbConnection()
  }

  private async testDbConnection() {
    try {
      await this.prisma.$queryRaw`SELECT 1`
      this.isDbAvailable = true
    }
    catch (error) {
      this.logger.warn('数据库连接失败，将使用文件配置模式:', error)
      this.isDbAvailable = false
    }
  }

  /**
   * 获取所有配置项
   *
   * @param {object} [options] 查询选项
   * @param {string} [options.category] 分类筛选
   * @param {boolean} [options.is_public] 是否公开
   * @param {boolean} [options.is_system] 是否系统项
   * @returns {Promise<ConfigItem[]>} 配置项列表
   */
  async getAllConfigs(options: {
    category?: string
    is_public?: boolean
    is_system?: boolean
  } = {}): Promise<ConfigItem[]> {
    if (!this.isDbAvailable) {
      return []
    }

    try {
      const where: any = {}
      if (options.category)
        where.category = options.category
      if (options.is_public !== undefined)
        where.is_public = options.is_public
      if (options.is_system !== undefined)
        where.is_system = options.is_system

      const configs = await this.prisma.app_config.findMany({
        where,
        orderBy: [
          { category: 'asc' },
          { config_key: 'asc' },
        ],
      })

      return configs as ConfigItem[]
    }
    catch (error) {
      this.logger.error('获取配置列表失败:', error)
      this.isDbAvailable = false
      return []
    }
  }

  /**
   * 根据键获取配置项
   *
   * @param config_key 配置键
   * @returns 配置项或null
   */
  async getConfigByKey(config_key: string): Promise<ConfigItem | null> {
    try {
      const config = await this.prisma.app_config.findUnique({
        where: { config_key },
      })
      return config as ConfigItem | null
    }
    catch (error) {
      this.logger.error(`获取配置失败: ${config_key}`, error)
      throw error
    }
  }

  /**
   * 获取配置值（自动类型转换）
   *
   * @param config_key 配置键
   * @returns 转换后的配置值
   */
  async getConfigValue<T = any>(config_key: string): Promise<T | null> {
    try {
      const config = await this.getConfigByKey(config_key)
      if (!config)
        return null

      return this.parseConfigValue(config.config_value, config.config_type) as T
    }
    catch (error) {
      this.logger.error(`解析配置值失败: ${config_key}`, error)
      return null
    }
  }

  /**
   * 创建配置项
   *
   * @param request 创建请求
   * @returns 创建的配置项
   */
  async createConfig(request: CreateConfigRequest): Promise<ConfigItem> {
    try {
      const config_type = request.config_type || this.detectConfigType(request.config_value)
      const config_value = this.stringifyConfigValue(request.config_value, config_type)

      const config = await this.prisma.app_config.create({
        data: {
          config_key: request.config_key,
          config_value,
          config_type,
          category: request.category || 'general',
          description: request.description,
          is_public: request.is_public ?? true,
          is_system: request.is_system ?? false,
        },
      })

      this.logger.info(`创建配置: ${request.config_key}`, { category: request.category })
      return config as ConfigItem
    }
    catch (error) {
      this.logger.error(`创建配置失败: ${request.config_key}`, error)
      throw error
    }
  }

  /**
   * 更新配置项
   *
   * @param config_key 配置键
   * @param request 更新请求
   * @returns 更新后的配置项
   */
  async updateConfig(config_key: string, request: UpdateConfigRequest): Promise<ConfigItem> {
    try {
      const updateData: any = {}

      if (request.config_value !== undefined) {
        const config_type = request.config_type || this.detectConfigType(request.config_value)
        updateData.config_value = this.stringifyConfigValue(request.config_value, config_type)
        updateData.config_type = config_type
      }

      if (request.category)
        updateData.category = request.category
      if (request.description !== undefined)
        updateData.description = request.description
      if (request.is_public !== undefined)
        updateData.is_public = request.is_public

      const config = await this.prisma.app_config.update({
        where: { config_key },
        data: updateData,
      })

      this.logger.info(`更新配置: ${config_key}`)
      return config as ConfigItem
    }
    catch (error) {
      this.logger.error(`更新配置失败: ${config_key}`, error)
      throw error
    }
  }

  /**
   * 删除配置项
   *
   * @param config_key 配置键
   */
  async deleteConfig(config_key: string): Promise<void> {
    try {
      // 检查是否为系统配置
      const config = await this.getConfigByKey(config_key)
      if (config?.is_system) {
        throw new Error('系统配置不能删除')
      }

      await this.prisma.app_config.delete({
        where: { config_key },
      })

      this.logger.info(`删除配置: ${config_key}`)
    }
    catch (error) {
      this.logger.error(`删除配置失败: ${config_key}`, error)
      throw error
    }
  }

  /**
   * 批量设置配置（从AppConfig对象）
   *
   * @param config AppConfig对象
   * @param category 配置分类
   */
  async setConfigsFromObject(config: Partial<AppConfig>, category?: string): Promise<void> {
    // 如果数据库不可用，跳过数据库操作
    if (!this.isDbAvailable) {
      this.logger.info('数据库不可用，跳过配置保存到数据库')
      return
    }

    try {
      const flatConfig = this.flattenConfig(config)

      for (const [key, value] of Object.entries(flatConfig)) {
        const existingConfig = await this.getConfigByKey(key)

        if (existingConfig) {
          await this.updateConfig(key, { config_value: value })
        }
        else {
          await this.createConfig({
            config_key: key,
            config_value: value,
            category: category || this.getCategoryFromKey(key),
            is_system: true, // 从代码设置的配置标记为系统配置
          })
        }
      }

      this.logger.info('批量设置配置完成', { count: Object.keys(flatConfig).length })
    }
    catch (error) {
      this.logger.error('批量设置配置失败:', error)
      // 不抛出错误，允许配置继续使用文件模式
      this.isDbAvailable = false
    }
  }

  /**
   * 获取完整的AppConfig对象（数据库配置 + 文件配置）
   *
   * @param defaultConfig 默认配置（文件配置）
   * @returns 合并后的完整配置
   */
  async getFullAppConfig(defaultConfig: AppConfig): Promise<AppConfig> {
    // 如果数据库不可用，直接返回默认配置
    if (!this.isDbAvailable) {
      this.logger.info('数据库不可用，使用文件配置')
      return defaultConfig
    }

    try {
      // 获取所有数据库配置
      const dbConfigs = await this.getAllConfigs()

      // 将数据库配置转换为嵌套对象
      const dbConfigObject = this.unflattenConfig(dbConfigs)

      // 深度合并：数据库配置覆盖默认配置
      const mergedConfig = this.deepMerge(defaultConfig, dbConfigObject)

      this.logger.debug('配置加载完成', {
        dbConfigCount: dbConfigs.length,
        hasDefaultConfig: !!defaultConfig,
      })

      return mergedConfig
    }
    catch (error) {
      this.logger.error('获取完整配置失败:', error)
      // 出错时标记数据库不可用并返回默认配置
      this.isDbAvailable = false
      return defaultConfig
    }
  }

  /**
   * 重置配置（清除所有非系统配置）
   */
  async resetConfigs(): Promise<void> {
    try {
      await this.prisma.app_config.deleteMany({
        where: { is_system: false },
      })

      this.logger.info('配置已重置（保留系统配置）')
    }
    catch (error) {
      this.logger.error('重置配置失败:', error)
      throw error
    }
  }

  // ============================================================================
  // 私有辅助方法
  // ============================================================================

  /**
   * 解析配置值
   */
  private parseConfigValue(value: string, type: string): any {
    try {
      switch (type) {
        case 'boolean':
          return value === 'true'
        case 'number':
          return Number(value)
        case 'object':
        case 'array':
          return JSON.parse(value)
        default:
          return value
      }
    }
    catch {
      return value // 解析失败时返回原始字符串
    }
  }

  /**
   * 序列化配置值
   */
  private stringifyConfigValue(value: any, type: string): string {
    switch (type) {
      case 'object':
      case 'array':
        return JSON.stringify(value)
      default:
        return String(value)
    }
  }

  /**
   * 自动检测配置类型
   */
  private detectConfigType(value: any): 'string' | 'number' | 'boolean' | 'object' | 'array' {
    if (typeof value === 'boolean')
      return 'boolean'
    if (typeof value === 'number')
      return 'number'
    if (Array.isArray(value))
      return 'array'
    if (typeof value === 'object' && value !== null)
      return 'object'
    return 'string'
  }

  /**
   * 扁平化配置对象
   */
  private flattenConfig(obj: any, prefix = ''): Record<string, any> {
    const result: Record<string, any> = {}

    for (const [key, value] of Object.entries(obj)) {
      const newKey = prefix ? `${prefix}.${key}` : key

      if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
        Object.assign(result, this.flattenConfig(value, newKey))
      }
      else {
        result[newKey] = value
      }
    }

    return result
  }

  /**
   * 反扁平化配置对象
   */
  private unflattenConfig(configs: ConfigItem[]): any {
    const result: any = {}

    for (const config of configs) {
      const keys = config.config_key.split('.')
      const value = this.parseConfigValue(config.config_value, config.config_type)

      let current = result
      for (let i = 0; i < keys.length - 1; i++) {
        const key = keys[i]
        if (!(key in current))
          current[key] = {}
        current = current[key]
      }

      current[keys[keys.length - 1]] = value
    }

    return result
  }

  /**
   * 从配置键推断分类
   */
  private getCategoryFromKey(key: string): string {
    const parts = key.split('.')
    if (parts.length > 0) {
      const category = parts[0]
      if (['proxy', 'network', 'booking', 'logging', 'gui', 'features', 'monitoring'].includes(category)) {
        return category
      }
    }
    return 'general'
  }

  /**
   * 深度合并对象
   */
  private deepMerge(target: any, source: any): any {
    const result = { ...target }

    for (const key in source) {
      if (source[key] !== null && typeof source[key] === 'object' && !Array.isArray(source[key])) {
        result[key] = this.deepMerge(target[key] || {}, source[key])
      }
      else {
        result[key] = source[key]
      }
    }

    return result
  }
}

// 全局服务实例
let configService: ConfigService | null = null

/**
 * 获取配置服务实例
 */
export function getConfigService(): ConfigService {
  if (!configService) {
    configService = new ConfigService()
  }
  return configService
}
